home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 4 / Amiga Tools 4.iso / grafix / tools / jpeg / jpeg-6a / rdrle.c < prev    next >
C/C++ Source or Header  |  1996-01-06  |  12KB  |  388 lines

  1. /*
  2.  * rdrle.c
  3.  *
  4.  * Copyright (C) 1991-1996, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains routines to read input images in Utah RLE format.
  9.  * The Utah Raster Toolkit library is required (version 3.1 or later).
  10.  *
  11.  * These routines may need modification for non-Unix environments or
  12.  * specialized applications.  As they stand, they assume input from
  13.  * an ordinary stdio stream.  They further assume that reading begins
  14.  * at the start of the file; start_input may need work if the
  15.  * user interface has already read some data (e.g., to determine that
  16.  * the file is indeed RLE format).
  17.  *
  18.  * Based on code contributed by Mike Lijewski,
  19.  * with updates from Robert Hutchinson.
  20.  */
  21.  
  22. #include "cdjpeg.h"        /* Common decls for cjpeg/djpeg applications */
  23.  
  24. #ifdef RLE_SUPPORTED
  25.  
  26. /* rle.h is provided by the Utah Raster Toolkit. */
  27.  
  28. #include <rle.h>
  29.  
  30. /*
  31.  * We assume that JSAMPLE has the same representation as rle_pixel,
  32.  * to wit, "unsigned char".  Hence we can't cope with 12- or 16-bit samples.
  33.  */
  34.  
  35. #if BITS_IN_JSAMPLE != 8
  36.   Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
  37. #endif
  38.  
  39. /*
  40.  * We support the following types of RLE files:
  41.  *   
  42.  *   GRAYSCALE   - 8 bits, no colormap
  43.  *   MAPPEDGRAY  - 8 bits, 1 channel colomap
  44.  *   PSEUDOCOLOR - 8 bits, 3 channel colormap
  45.  *   TRUECOLOR   - 24 bits, 3 channel colormap
  46.  *   DIRECTCOLOR - 24 bits, no colormap
  47.  *
  48.  * For now, we ignore any alpha channel in the image.
  49.  */
  50.  
  51. typedef enum
  52.   { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;
  53.  
  54.  
  55. /*
  56.  * Since RLE stores scanlines bottom-to-top, we have to invert the image
  57.  * to conform to JPEG's top-to-bottom order.  To do this, we read the
  58.  * incoming image into a virtual array on the first get_pixel_rows call,
  59.  * then fetch the required row from the virtual array on subsequent calls.
  60.  */
  61.  
  62. typedef struct _rle_source_struct * rle_source_ptr;
  63.  
  64. typedef struct _rle_source_struct {
  65.   struct cjpeg_source_struct pub; /* public fields */
  66.  
  67.   rle_kind visual;              /* actual type of input file */
  68.   jvirt_sarray_ptr image;       /* virtual array to hold the image */
  69.   JDIMENSION row;        /* current row # in the virtual array */
  70.   rle_hdr header;               /* Input file information */
  71.   rle_pixel** rle_row;          /* holds a row returned by rle_getrow() */
  72.  
  73. } rle_source_struct;
  74.  
  75.  
  76. /*
  77.  * Read the file header; return image size and component count.
  78.  */
  79.  
  80. METHODDEF(void)
  81. start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  82. {
  83.   rle_source_ptr source = (rle_source_ptr) sinfo;
  84.   JDIMENSION width, height;
  85. #ifdef PROGRESS_REPORT
  86.   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
  87. #endif
  88.  
  89.   /* Use RLE library routine to get the header info */
  90.   source->header = *rle_hdr_init(NULL);
  91.   source->header.rle_file = source->pub.input_file;
  92.   switch (rle_get_setup(&(source->header))) {
  93.   case RLE_SUCCESS:
  94.     /* A-OK */
  95.     break;
  96.   case RLE_NOT_RLE:
  97.     ERREXIT(cinfo, JERR_RLE_NOT);
  98.     break;
  99.   case RLE_NO_SPACE:
  100.     ERREXIT(cinfo, JERR_RLE_MEM);
  101.     break;
  102.   case RLE_EMPTY:
  103.     ERREXIT(cinfo, JERR_RLE_EMPTY);
  104.     break;
  105.   case RLE_EOF:
  106.     ERREXIT(cinfo, JERR_RLE_EOF);
  107.     break;
  108.   default:
  109.     ERREXIT(cinfo, JERR_RLE_BADERROR);
  110.     break;
  111.   }
  112.  
  113.   /* Figure out what we have, set private vars and return values accordingly */
  114.   
  115.   width  = source->header.xmax - source->header.xmin + 1;
  116.   height = source->header.ymax - source->header.ymin + 1;
  117.   source->header.xmin = 0;        /* realign horizontally */
  118.   source->header.xmax = width-1;
  119.  
  120.   cinfo->image_width      = width;
  121.   cinfo->image_height     = height;
  122.   cinfo->data_precision   = 8;  /* we can only handle 8 bit data */
  123.  
  124.   if (source->header.ncolors == 1 && source->header.ncmap == 0) {
  125.     source->visual     = GRAYSCALE;
  126.     TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);
  127.   } else if (source->header.ncolors == 1 && source->header.ncmap == 1) {
  128.     source->visual     = MAPPEDGRAY;
  129.     TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,
  130.              1 << source->header.cmaplen);
  131.   } else if (source->header.ncolors == 1 && source->header.ncmap == 3) {
  132.     source->visual     = PSEUDOCOLOR;
  133.     TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,
  134.          1 << source->header.cmaplen);
  135.   } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
  136.     source->visual     = TRUECOLOR;
  137.     TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
  138.          1 << source->header.cmaplen);
  139.   } else if (source->header.ncolors == 3 && source->header.ncmap == 0) {
  140.     source->visual     = DIRECTCOLOR;
  141.     TRACEMS2(cinfo, 1, JTRC_RLE, width, height);
  142.   } else
  143.     ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);
  144.   
  145.   if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {
  146.     cinfo->in_color_space   = JCS_GRAYSCALE;
  147.     cinfo->input_components = 1;
  148.   } else {
  149.     cinfo->in_color_space   = JCS_RGB;
  150.     cinfo->input_components = 3;
  151.   }
  152.  
  153.   /*
  154.    * A place to hold each scanline while it's converted.
  155.    * (GRAYSCALE scanlines don't need converting)
  156.    */
  157.   if (source->visual != GRAYSCALE) {
  158.     source->rle_row = (rle_pixel**) (*cinfo->mem->alloc_sarray)
  159.       ((j_common_ptr) cinfo, JPOOL_IMAGE,
  160.        (JDIMENSION) width, (JDIMENSION) cinfo->input_components);
  161.   }
  162.  
  163.   /* request a virtual array to hold the image */
  164.   source->image = (*cinfo->mem->request_virt_sarray)
  165.     ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
  166.      (JDIMENSION) (width * source->header.ncolors),
  167.      (JDIMENSION) height, (JDIMENSION) 1);
  168.  
  169. #ifdef PROGRESS_REPORT
  170.   if (progress != NULL) {
  171.     /* count file input as separate pass */
  172.     progress->total_extra_passes++;
  173.   }
  174. #endif
  175.  
  176.   source->pub.buffer_height = 1;
  177. }
  178.  
  179.  
  180. /*
  181.  * Read one row of pixels.
  182.  * Called only after load_image has read the image into the virtual array.
  183.  * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
  184.  */
  185.  
  186. METHODDEF(JDIMENSION)
  187. get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  188. {
  189.   rle_source_ptr source = (rle_source_ptr) sinfo;
  190.  
  191.   source->row--;
  192.   source->pub.buffer = (*cinfo->mem->access_virt_sarray)
  193.     ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
  194.  
  195.   return 1;
  196. }
  197.  
  198. /*
  199.  * Read one row of pixels.
  200.  * Called only after load_image has read the image into the virtual array.
  201.  * Used for PSEUDOCOLOR images.
  202.  */
  203.  
  204. METHODDEF(JDIMENSION)
  205. get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  206. {
  207.   rle_source_ptr source = (rle_source_ptr) sinfo;
  208.   JSAMPROW src_row, dest_row;
  209.   JDIMENSION col;
  210.   rle_map *colormap;
  211.   int val;
  212.  
  213.   colormap = source->header.cmap;
  214.   dest_row = source->pub.buffer[0];
  215.   source->row--;
  216.   src_row = * (*cinfo->mem->access_virt_sarray)
  217.     ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
  218.  
  219.   for (col = cinfo->image_width; col > 0; col--) {
  220.     val = GETJSAMPLE(*src_row++);
  221.     *dest_row++ = (JSAMPLE) (colormap[val      ] >> 8);
  222.     *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
  223.     *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
  224.   }
  225.  
  226.   return 1;
  227. }
  228.  
  229.  
  230. /*
  231.  * Load the image into a virtual array.  We have to do this because RLE
  232.  * files start at the lower left while the JPEG standard has them starting
  233.  * in the upper left.  This is called the first time we want to get a row
  234.  * of input.  What we do is load the RLE data into the array and then call
  235.  * the appropriate routine to read one row from the array.  Before returning,
  236.  * we set source->pub.get_pixel_rows so that subsequent calls go straight to
  237.  * the appropriate row-reading routine.
  238.  */
  239.  
  240. METHODDEF(JDIMENSION)
  241. load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  242. {
  243.   rle_source_ptr source = (rle_source_ptr) sinfo;
  244.   JDIMENSION row, col;
  245.   JSAMPROW  scanline, red_ptr, green_ptr, blue_ptr;
  246.   rle_pixel **rle_row;
  247.   rle_map *colormap;
  248.   char channel;
  249. #ifdef PROGRESS_REPORT
  250.   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
  251. #endif
  252.  
  253.   colormap = source->header.cmap;
  254.   rle_row = source->rle_row;
  255.  
  256.   /* Read the RLE data into our virtual array.
  257.    * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
  258.    * and (b) we are not on a machine where FAR pointers differ from regular.
  259.    */
  260.   RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */
  261.  
  262. #ifdef PROGRESS_REPORT
  263.   if (progress != NULL) {
  264.     progress->pub.pass_limit = cinfo->image_height;
  265.     progress->pub.pass_counter = 0;
  266.     (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  267.   }
  268. #endif
  269.  
  270.   switch (source->visual) {
  271.  
  272.   case GRAYSCALE:
  273.   case PSEUDOCOLOR:
  274.     for (row = 0; row < cinfo->image_height; row++) {
  275.       rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
  276.          ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
  277.       rle_getrow(&source->header, rle_row);
  278. #ifdef PROGRESS_REPORT
  279.       if (progress != NULL) {
  280.         progress->pub.pass_counter++;
  281.         (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  282.       }
  283. #endif
  284.     }
  285.     break;
  286.  
  287.   case MAPPEDGRAY:
  288.   case TRUECOLOR:
  289.     for (row = 0; row < cinfo->image_height; row++) {
  290.       scanline = * (*cinfo->mem->access_virt_sarray)
  291.         ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
  292.       rle_row = source->rle_row;
  293.       rle_getrow(&source->header, rle_row);
  294.  
  295.       for (col = 0; col < cinfo->image_width; col++) {
  296.         for (channel = 0; channel < source->header.ncolors; channel++) {
  297.           *scanline++ = (JSAMPLE)
  298.             (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
  299.         }
  300.       }
  301.  
  302. #ifdef PROGRESS_REPORT
  303.       if (progress != NULL) {
  304.         progress->pub.pass_counter++;
  305.         (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  306.       }
  307. #endif
  308.     }
  309.     break;
  310.  
  311.   case DIRECTCOLOR:
  312.     for (row = 0; row < cinfo->image_height; row++) {
  313.       scanline = * (*cinfo->mem->access_virt_sarray)
  314.         ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
  315.       rle_getrow(&source->header, rle_row);
  316.  
  317.       red_ptr   = rle_row[0];
  318.       green_ptr = rle_row[1];
  319.       blue_ptr  = rle_row[2];
  320.  
  321.       for (col = cinfo->image_width; col > 0; col--) {
  322.         *scanline++ = *red_ptr++;
  323.         *scanline++ = *green_ptr++;
  324.         *scanline++ = *blue_ptr++;
  325.       }
  326.  
  327. #ifdef PROGRESS_REPORT
  328.       if (progress != NULL) {
  329.         progress->pub.pass_counter++;
  330.         (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  331.       }
  332. #endif
  333.     }
  334.   }
  335.  
  336. #ifdef PROGRESS_REPORT
  337.   if (progress != NULL)
  338.     progress->completed_extra_passes++;
  339. #endif
  340.  
  341.   /* Set up to call proper row-extraction routine in future */
  342.   if (source->visual == PSEUDOCOLOR) {
  343.     source->pub.buffer = source->rle_row;
  344.     source->pub.get_pixel_rows = get_pseudocolor_row;
  345.   } else {
  346.     source->pub.get_pixel_rows = get_rle_row;
  347.   }
  348.   source->row = cinfo->image_height;
  349.  
  350.   /* And fetch the topmost (bottommost) row */
  351.   return (*source->pub.get_pixel_rows) (cinfo, sinfo);   
  352. }
  353.  
  354.  
  355. /*
  356.  * Finish up at the end of the file.
  357.  */
  358.  
  359. METHODDEF(void)
  360. finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  361. {
  362.   /* no work */
  363. }
  364.  
  365.  
  366. /*
  367.  * The module selection routine for RLE format input.
  368.  */
  369.  
  370. GLOBAL(cjpeg_source_ptr)
  371. jinit_read_rle (j_compress_ptr cinfo)
  372. {
  373.   rle_source_ptr source;
  374.  
  375.   /* Create module interface object */
  376.   source = (rle_source_ptr)
  377.       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  378.                                   SIZEOF(rle_source_struct));
  379.   /* Fill in method ptrs */
  380.   source->pub.start_input = start_input_rle;
  381.   source->pub.finish_input = finish_input_rle;
  382.   source->pub.get_pixel_rows = load_image;
  383.  
  384.   return (cjpeg_source_ptr) source;
  385. }
  386.  
  387. #endif /* RLE_SUPPORTED */
  388.